package org.study.es.api.client;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch.cat.IndicesResponse;
import co.elastic.clients.elasticsearch.cat.indices.IndicesRecord;
import co.elastic.clients.elasticsearch.indices.*;
import co.elastic.clients.elasticsearch.indices.get_alias.IndexAliases;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.endpoints.BooleanResponse;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.study.es.api.constant.EsConstants;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 索引基本操作
 *
 * @author doveylovey
 * @version v1.0.0
 * @email 1135782208@qq.com
 * @date 2023年06月03日
 */
@Slf4j
public class RestClientUtils {
    public static ElasticsearchClient getElasticsearchClient1() {
        RestClient restClient = RestClient.builder(new HttpHost(EsConstants.HOST, EsConstants.PORT))
                .setRequestConfigCallback(requestConfigCallback -> {
                    requestConfigCallback.setConnectTimeout(-1);
                    requestConfigCallback.setSocketTimeout(-1);
                    requestConfigCallback.setConnectionRequestTimeout(-1);
                    return requestConfigCallback;
                })
                .build();
        ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
        ElasticsearchClient client = new ElasticsearchClient(transport);
        return client;
    }

    public static ElasticsearchClient getElasticsearchClient() {
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(EsConstants.USERNAME, EsConstants.PASSWORD));
        RestClient restClient = RestClient.builder(new HttpHost(EsConstants.HOST, EsConstants.PORT))
                .setRequestConfigCallback(requestConfigCallback -> {
                    requestConfigCallback.setConnectTimeout(-1);
                    requestConfigCallback.setSocketTimeout(-1);
                    requestConfigCallback.setConnectionRequestTimeout(-1);
                    return requestConfigCallback;
                })
                .setHttpClientConfigCallback(httpClientConfigCallback -> {
                    httpClientConfigCallback.setDefaultCredentialsProvider(credentialsProvider);
                    return httpClientConfigCallback;
                })
                .build();
        ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
        ElasticsearchClient client = new ElasticsearchClient(transport);
        return client;
    }

    /**
     * 创建索引
     *
     * @param indexName
     * @return boolean
     */
    public static boolean createIndex(String indexName) throws IOException {
        ElasticsearchClient client = getElasticsearchClient();
        // CreateIndexResponse response = client.indices().create(CreateIndexRequest.of(builder -> builder.index(indexName)));
        CreateIndexResponse response = client.indices().create(builder -> builder.index(indexName));
        boolean acknowledged = response.acknowledged();
        log.info("创建索引：{}，结果：{}", indexName, acknowledged);
        return acknowledged;

    }

    /**
     * 创建索引，同时指定映射
     *
     * @param indexName
     * @param documentMapping
     * @return boolean
     */
    public static boolean createIndexWithMapping(String indexName, Map<String, Property> documentMapping) throws IOException {
        ElasticsearchClient client = getElasticsearchClient();
        // CreateIndexResponse response = client.indices().create(CreateIndexRequest.of(builder -> builder.index(indexName).mappings(mapping -> mapping.properties(documentMapping))));
        CreateIndexResponse response = client.indices().create(builder -> builder.index(indexName).mappings(mapping -> mapping.properties(documentMapping)));
        boolean acknowledged = response.acknowledged();
        log.info("创建索引：{}，结果：{}", indexName, acknowledged);
        return acknowledged;
    }

    /**
     * 判断索引是否存在
     *
     * @param indexName
     * @return boolean
     */
    public static boolean existsIndex(String indexName) throws IOException {
        ElasticsearchClient client = getElasticsearchClient();
        // BooleanResponse response = client.indices().exists(ExistsRequest.of(builder -> builder.index(indexName)));
        BooleanResponse response = client.indices().exists(builder -> builder.index(indexName));
        boolean exists = response.value();
        log.info("判断索引：{}是否存在，结果：{}", indexName, exists);
        return exists;
    }

    /**
     * 删除索引：删除前可以检验下索引是否存在
     *
     * @param indexName
     * @return boolean
     */
    public static boolean deleteIndex(String indexName) throws IOException {
        ElasticsearchClient client = getElasticsearchClient();
        // DeleteIndexResponse response = client.indices().delete(DeleteIndexRequest.of(builder -> builder.index(indexName)));
        DeleteIndexResponse response = client.indices().delete(builder -> builder.index(indexName));
        boolean acknowledged = response.acknowledged();
        log.info("删除索引：{}，结果：{}", indexName, acknowledged);
        return acknowledged;
    }

    /**
     * 删除索引(批量)：删除前可以检验下索引是否存在
     *
     * @param indexNameList
     * @return boolean
     */
    public static boolean deleteIndex(List<String> indexNameList) throws IOException {
        ElasticsearchClient client = getElasticsearchClient();
        // DeleteIndexResponse response = client.indices().delete(DeleteIndexRequest.of(builder -> builder.index(indexNameList)));
        DeleteIndexResponse response = client.indices().delete(builder -> builder.index(indexNameList));
        boolean acknowledged = response.acknowledged();
        log.info("删除索引(批量)：{}，结果：{}", indexNameList, acknowledged);
        return acknowledged;
    }

    /**
     * 查询索引：如果查询的indexName不存在，会抛出index_not_found_exception
     *
     * @param indexName
     * @return java.util.Map<java.lang.String, co.elastic.clients.elasticsearch.indices.IndexState>
     */
    public static Map<String, IndexState> getIndex(String indexName) throws IOException {
        ElasticsearchClient client = getElasticsearchClient();
        // GetIndexResponse response = client.indices().get(GetIndexRequest.of(builder -> builder.index(indexName)));
        GetIndexResponse response = client.indices().get(builder -> builder.index(indexName));
        Map<String, IndexState> result = response.result();
        log.info("查询索引：{}，结果：{}", indexName, result.toString());
        return result;
    }

    /**
     * 查询索引(批量)：如果查询的indexName不存在，会抛出index_not_found_exception
     *
     * @param indexNameList
     * @return java.util.Map<java.lang.String, co.elastic.clients.elasticsearch.indices.IndexState>
     */
    public static Map<String, IndexState> getIndex(List<String> indexNameList) throws IOException {
        ElasticsearchClient client = getElasticsearchClient();
        // GetIndexResponse response = client.indices().get(GetIndexRequest.of(builder -> builder.index(indexNameList)));
        GetIndexResponse response = client.indices().get(builder -> builder.index(indexNameList));
        Map<String, IndexState> result = response.result();
        log.info("查询索引：{}，结果：{}", indexNameList, result.toString());
        return result;
    }

    /**
     * 查询索引(全部)
     *
     * @param
     * @return java.util.List<co.elastic.clients.elasticsearch.cat.indices.IndicesRecord>
     */
    public static List<IndicesRecord> getAllIndex() throws IOException {
        ElasticsearchClient client = getElasticsearchClient();
        IndicesResponse response = client.cat().indices();
        List<IndicesRecord> indicesRecordList = response.valueBody();
        log.info("查询全部索引结果：{}", indicesRecordList);
        return indicesRecordList;
    }

    /**
     * 添加别名
     *
     * @param indexName 索引名称
     * @param aliasName 别名名称
     * @return
     * @throws IOException
     */
    public static boolean addAliases(String indexName, String aliasName) throws IOException {
        ElasticsearchClient client = getElasticsearchClient();
        // UpdateAliasesResponse response = client.indices().updateAliases(UpdateAliasesRequest.of(builder -> builder.actions(action -> action.add(add -> add.index(indexName).alias(aliasName)))));
        UpdateAliasesResponse response = client.indices().updateAliases(builder -> builder.actions(action -> action.add(add -> add.index(indexName).alias(aliasName))));
        boolean acknowledged = response.acknowledged();
        log.info("给索引：{}，添加别名：{}，结果：{}", indexName, aliasName, acknowledged);
        return acknowledged;
    }

    /**
     * 添加别名(批量)：分别给每个索引添加多个别名
     *
     * @param indexNameList 索引名称
     * @param aliasNameList 别名名称
     * @return
     * @throws IOException
     */
    public static boolean addAliases(List<String> indexNameList, List<String> aliasNameList) throws IOException {
        ElasticsearchClient client = getElasticsearchClient();
        // UpdateAliasesResponse response = client.indices().updateAliases(UpdateAliasesRequest.of(builder -> builder.actions(action -> action.add(add -> add.indices(indexNameList).aliases(aliasNameList)))));
        UpdateAliasesResponse response = client.indices().updateAliases(builder -> builder.actions(action -> action.add(add -> add.indices(indexNameList).aliases(aliasNameList))));
        boolean acknowledged = response.acknowledged();
        log.info("给索引：{}，添加别名：{}，结果：{}", indexNameList, aliasNameList, acknowledged);
        return acknowledged;
    }

    /**
     * 移除别名
     *
     * @param indexName
     * @param aliasName
     * @throws IOException
     */
    public static boolean deleteAlias(String indexName, String aliasName) throws IOException {
        ElasticsearchClient client = getElasticsearchClient();
        // DeleteAliasResponse response = client.indices().deleteAlias(DeleteAliasRequest.of(builder -> builder.index(indexName).name(aliasName)));
        DeleteAliasResponse response = client.indices().deleteAlias(builder -> builder.index(indexName).name(aliasName));
        boolean acknowledged = response.acknowledged();
        log.info("删除索引：{}的别名：{}，结果：{}", indexName, aliasName, acknowledged);
        return acknowledged;
    }

    /**
     * 移除别名(批量)：分别移除每个索引的多个别名
     *
     * @param indexNameList
     * @param aliasNameList
     * @throws IOException
     */
    public static boolean deleteAlias(List<String> indexNameList, List<String> aliasNameList) throws IOException {
        ElasticsearchClient client = getElasticsearchClient();
        // DeleteAliasResponse response = client.indices().deleteAlias(DeleteAliasRequest.of(builder -> builder.index(indexNameList).name(aliasNameList)));
        DeleteAliasResponse response = client.indices().deleteAlias(builder -> builder.index(indexNameList).name(aliasNameList));
        boolean acknowledged = response.acknowledged();
        log.info("删除索引：{}的别名：{}，结果：{}", indexNameList, aliasNameList, acknowledged);
        return acknowledged;
    }

    /**
     * 根据别名查询索引信息
     *
     * @param aliasName
     * @throws IOException
     */
    public static Map<String, IndexAliases> getIndexByAlias(String aliasName) throws IOException {
        ElasticsearchClient client = getElasticsearchClient();
        // GetAliasResponse response = client.indices().getAlias(GetAliasRequest.of(builder -> builder.name(aliasName)));
        GetAliasResponse response = client.indices().getAlias(builder -> builder.name(aliasName));
        Map<String, IndexAliases> result = response.result();
        log.info("根据别名：{}查询索引信息，结果：{}", aliasName, result);
        return result;
    }

    /**
     * 根据别名查询索引信息(批量)
     *
     * @param aliasNameList
     * @throws IOException
     */
    public static Map<String, IndexAliases> getIndexByAliases(List<String> aliasNameList) throws IOException {
        ElasticsearchClient client = getElasticsearchClient();
        // GetAliasResponse response = client.indices().getAlias(GetAliasRequest.of(builder -> builder.name(aliasNameList)));
        GetAliasResponse response = client.indices().getAlias(builder -> builder.name(aliasNameList));
        Map<String, IndexAliases> result = response.result();
        log.info("根据别名：{}查询索引信息，结果：{}", aliasNameList, result);
        return result;
    }

    /**
     * 根据别名查询索引名称
     *
     * @param aliasName
     * @throws IOException
     */
    public static List<String> getIndexNameByAlias(String aliasName) throws IOException {
        ElasticsearchClient client = getElasticsearchClient();
        List<String> indexList = new ArrayList<>();
        // GetAliasResponse response = client.indices().getAlias(GetAliasRequest.of(builder -> builder.name(aliasName)));
        GetAliasResponse response = client.indices().getAlias(builder -> builder.name(aliasName));
        Map<String, IndexAliases> result = response.result();
        if (MapUtils.isNotEmpty(result)) {
            indexList = result.keySet().stream().collect(Collectors.toList());
        }
        log.info("根据别名：{}查询索引名称，结果：{}", aliasName, result);
        return indexList;
    }

    /**
     * 根据别名查询索引名称(批量)
     *
     * @param aliasNameList
     * @throws IOException
     */
    public static List<String> getIndexNameByAliases(List<String> aliasNameList) throws IOException {
        ElasticsearchClient client = getElasticsearchClient();
        List<String> indexList = new ArrayList<>();
        // GetAliasResponse response = client.indices().getAlias(GetAliasRequest.of(builder -> builder.name(aliasNameList)));
        GetAliasResponse response = client.indices().getAlias(builder -> builder.name(aliasNameList));
        Map<String, IndexAliases> result = response.result();
        if (MapUtils.isNotEmpty(result)) {
            indexList = result.keySet().stream().collect(Collectors.toList());
        }
        log.info("根据别名：{}查询索引名称，结果：{}", aliasNameList, result);
        return indexList;
    }
}
